mod cmd;

use base::{
    base::{VBase, VMap},
    client::Client,
    err, err_value, ok, throw_err, ECode, Resp,
};
use futures_util::TryStreamExt;
use serde_json::{json, Value};
use std::time::Instant;
use tracing::{instrument, warn};
use warp::multipart::{FormData, Part};
use warp::{
    reject::Rejection,
    reply::{Json, WithStatus},
};

#[instrument(skip_all, name = "do_upload")]
pub async fn do_upload(
    para: String,
    form: FormData,
    client: &Client,
) -> Result<WithStatus<Json>, Rejection> {
    let start = Instant::now();

    let ret: Vec<_> = match form
        .and_then(|mut field| {
            let cmd = para.clone();

            async move {
                match cmd::do_cmd(&cmd, &mut field, client).await {
                    Ok(v) => Ok((v, Value::Null)),
                    Err(e) => {
                        warn!("upload error: {:?}, cmd: {:?}", e, cmd);
                        Ok((Value::Null, e))
                    }
                }
            }
        })
        .try_collect()
        .await
    {
        Ok(v) => v,
        Err(e) => {
            let duration = start.elapsed();
            warn!("dt: {:?} - error: {:?} - cmd: {:?}", duration, &e, para);

            let e = err_value(ECode::FileWrite, e.to_string());
            return Ok(base::ret_err(&e, None));
        }
    };

    match ret.first() {
        Some((ok, err)) => {
            if *ok == Value::Null {
                return Ok(base::ret_err(err, None));
            }

            Ok(base::ret_ok(ok))
        }
        None => {
            let e = err_value(ECode::FileWrite, "no file save");
            Ok(base::ret_err(&e, None))
        }
    }
}

pub fn get_dir() -> String {
    if cfg!(windows) {
        "./files/".to_string()
    } else {
        "/files/".to_string()
    }
}
